home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / csrc720j.lzh / mbtnc.c < prev    next >
C/C++ Source or Header  |  1993-08-23  |  17KB  |  806 lines

  1. /*
  2.  *  MBTNC.C - 12/20/92 - Deal with the tnc.
  3.  */
  4.  
  5. #include "mb.h"
  6.  
  7. #ifdef MCH_AMIGA
  8. extern PORTS *devtnc;   /* Set by inittnc() in amiga.c */
  9. extern char conn_direction;
  10. char *tcmds[] =
  11. #else
  12. static char *tcmds[] =
  13. #endif
  14. {
  15.   "cono on\n",
  16.   "cono of\n",
  17.   "m on\n",
  18.   "m of\n"
  19. };
  20.  
  21. #ifdef MCH_AMIGA
  22. extern char tmpstr[];
  23. extern short debug;
  24. extern unsigned char vhfstream,hfstream;
  25. word save_mode;
  26.  
  27. /* FIX 12
  28.    The KAM does not just say "*** DISCO" if you send a disco command and
  29.    it is already disconnected. No! That would be too easy. It says:
  30.    'Can't DISCONNECT, A/V Link state is: DISCONNECTED'
  31.    This can tie distnc() up in loop.
  32.    So look for this as well.
  33. */
  34. isother(cp)
  35. char *cp;
  36. {
  37.    if(search(cp,"Can't DISCO",11))return true;
  38.    return false;
  39. }
  40. #endif
  41.  
  42. isdis(cp)
  43. char *cp;
  44. {
  45.   if (search(cp, "*** DISC", 8)) return true;
  46.   return false;
  47. }
  48.  
  49. isreq(cp)
  50. char *cp;
  51. {
  52.   if (matchn(cp, "*** conn", 8)) return true;
  53.   if (matchn(cp, "*** Conn", 8)) return true;
  54.   return false;
  55. }
  56.  
  57. islink(cp)
  58. char *cp;
  59. {
  60.   return matchn(cp, "*** LINK", 8);
  61. }
  62.  
  63. iscon(cp)
  64. char *cp;
  65. {
  66.   return search(cp, "*** CONN", 8);
  67. }
  68.  
  69. isretry(cp)
  70. char *cp;
  71. {
  72.   if (matchn(cp, "*** Retry count exceeded", 24)) return true;
  73.   if (matchn(cp, "*** retry count exceeded", 24)) return true;
  74.   return false;
  75. }
  76. alloff()
  77. {
  78. #ifdef MCH_AMIGA
  79.    PORTS *p;
  80.   if(devtnc->dev == p_serial) {
  81.       if(port->mode & ops) {
  82.          p = port;
  83.          ioport(devtnc);
  84.          outstr("ATS0=0\n");
  85.          waitcmd(2);
  86.          ioport(p);
  87.       }
  88.       return;
  89.   }
  90. #endif
  91.   allcmd(t_coff);  /* Turn off connects */
  92.   allcmd(t_moff);  /* Turn off monitoring */
  93. }
  94.  
  95. allon()
  96. {
  97. #ifdef MCH_AMIGA
  98.    PORTS *p;
  99.   if(devtnc->dev == p_serial) {
  100.       if(port->mode & ops) {
  101.          p = port;
  102.          ioport(devtnc);
  103.          outstr("ATS0=2\n");
  104.          waitcmd(2);
  105.          ioport(p);
  106.       }
  107.       return;
  108.   }
  109. #endif
  110.   allcmd(t_mon);  /* Turn on monitoring */
  111.   allcmd(t_con);  /* Turn on connects  */
  112. }
  113.  
  114. login()
  115. {
  116.   register PORTS *p;
  117.   register char *i;
  118.  
  119.   readmsg();
  120.   readusr();
  121.  
  122.   p = port;
  123.  
  124.   p->lport = cport;
  125.   cport->lport = p;
  126.   p->errors = 0;
  127.   p->msg    = NULL;
  128.   p->cmdcnt = 0;
  129.   p->flags clrbit p_opreq;
  130.   p->ec = p->ecuser;
  131.  
  132. /*
  133.  *  Prepare to check if this user can indeed connect.
  134.  */
  135.  
  136.   switch (p->dev)
  137.   {
  138.     case p_console:
  139.       p->mode = local;
  140.       alloff();
  141.       rduser(p->user->call, p->user);
  142.       unbl(p->line, p->user->call, ln_call);
  143.       log('C', 'S', ' ', p->line);
  144.       break;
  145.  
  146.     case p_tnc:
  147.       p->mode = remote;
  148.       tncstate();   /* Pick up the "... connected to ..." line */
  149. #ifdef MCH_AMIGA
  150. /* FIX 8 */
  151.       /* Was this a valid connect? If the BBS saw "*** CONN" but the TNC
  152.          is disconnected (both hf and vhf), then it was monitoring someone's
  153.          data and it is not a valid connection, so log a bad one and get
  154.          out. Need to do same thing when connected to a user who is stupid
  155.          enough to send data that looks like a disconnect.
  156.       */
  157.       if(p->mode == discon) {
  158.          /* force the mode to idle ... the user was never there.
  159.             discon means user was there and then disconnected
  160.          */
  161.          p->mode = idle;
  162.          /* type 'E' log is for errors .... prtlog ignores them */
  163.          /* EF is for the false connected message */
  164.          log('E','F',' ',p->line);
  165.          return;
  166.       }
  167. #endif
  168.       alloff();
  169.       if (p->tmode) trantnc(); else convtnc();
  170. /*
  171.  *  Remove the "; 1 unacked" that pk-232 puts on status line.
  172.  */
  173.       if ((i = strchr(p->line, ';')) isnt NULL) *i = '\0';
  174.       if ((i = strchr(p->line, '*')) isnt NULL) *i = '\0';
  175.       strcpy(p->line, p->line + 28);
  176.  
  177.       logina(false);
  178.       log('C', p->id, ' ', p->line);
  179.       break;
  180.  
  181. #ifdef MCH_AMIGA
  182.     case p_nulmdm:
  183. #endif
  184.     case p_serial:
  185.       p->mode = remote;
  186.       p->flags setbit p_trans;
  187.       alloff();
  188.       strcpy(p->line, p->line + 17);
  189.       logina(false);
  190.       log('C', p->id, ' ', p->line);
  191.       break;
  192.  
  193.     default: ;
  194.   }
  195. }
  196.  
  197. /*
  198.  *  The login checking process.
  199.  */
  200.  
  201. logina(link)
  202. short link;
  203. {
  204.   register char *p, *q;
  205.   register int ssid;
  206.   register short nd;
  207.  
  208.   char bullfile[11];
  209.  
  210.   remnl(port->line);
  211.  
  212. /*
  213.  *  Clear any pending connect request.
  214.  */
  215.  
  216.   port->flags clrbit p_req;
  217.  
  218. /*
  219.  *  Get the users call and ssid.
  220.  */
  221.  
  222.   parse();
  223.   ssid = pcall(tcall, port->fld[0]);
  224.  
  225. /*
  226.  *  Add the call to J list for port, and for connect.
  227.  */
  228.  
  229.   addcall(port->fld[0], cport);
  230.   addcall(port->fld[0], port);
  231.  
  232. /*
  233.  *  Save call of connected gateway, if user linked here.
  234.  */
  235.  
  236.   if (link) strncpy(tmp->scr, port->user->call, ln_call);
  237.  
  238. /*
  239.  *  Get (or make) this users user record.
  240.  */
  241.  
  242.   rduser(tcall, port->user);
  243.  
  244. /*
  245.  *  Update the data in the user record.
  246.  */
  247.  
  248.   port->user->ssid = ssid;
  249.   if (link) port->user->port = 'L'; else port->user->port = port->id;
  250.  
  251. /*
  252.  *  Get path. Count how many digi in path.
  253.  *  First, fix digi path in case is a PK-232.
  254.  */
  255.  
  256.   nd = 3;
  257.   while (port->flds > 3)
  258.   {
  259.     strcat(port->fld[2], port->fld[nd]);
  260.     port->flds--;
  261.     nd++;
  262.   }
  263.  
  264.   nd = 0;
  265.  
  266.   if (link) unbl(port->user->path, tmp->scr, ln_call);
  267.   else if (port->flds > 2)
  268.   {
  269.     nd++;
  270.     p = port->user->path;
  271.     for (q = port->fld[2]; *q; q++)
  272.       if (*q isnt ' ') if ((*p++ = *q) is ',') nd++;
  273.     *p = '\0';
  274.   }
  275.   else *port->user->path = '\0';
  276.  
  277. /*
  278.  *  If this user is excluded, exclude him.
  279.  */
  280.  
  281.   if (port->user->options & u_exclude) { port->mode = exclude; return; }
  282.  
  283. /*
  284.  *  At last, decide if this user CAN connect.
  285.  *  If sysop or bbs, can always connect.
  286.  */
  287.  
  288.   if (port->user->options & (u_sysop | u_bbs)) {
  289. #ifdef MCH_AMIGA
  290.    conn_direction = '<';
  291.    user_title(port->user->call);
  292. #endif
  293.     outstr(vers);
  294.     return;
  295.   }
  296.  
  297. /*
  298.  *  If this turkey has illegal call, kick him right off.
  299.  */
  300.  
  301.   if (port->priv & p_ilcal) if (!iscall(tcall)) { port->mode = exclude; return; }
  302.  
  303. /*
  304.  *  This user isn't a bbs. If port is bbs only, bye bye.
  305.  */
  306.  
  307.   if (port->priv & p_bbs) { port->mode = exclude; return; }
  308.  
  309. /*
  310.  *  If user connected through too many digi, bye bye.
  311.  */
  312.  
  313.   if (nd > port->ndigi) { port->mode = exclude; return; }
  314.  
  315. /*
  316.  *  Well, this user can indeed connect on this port.
  317.  *  Send our "I am a machine message"
  318.  */
  319.  
  320.   outstr(vers);
  321.  
  322. #ifdef MCH_AMIGA
  323. /* Put the call in the title bar */
  324.    conn_direction = '<';
  325.    user_title(port->user->call);
  326. #endif
  327.  
  328.   sprintf(bullfile, "BULLETIN.%c",port->id);
  329.   if ((port->fl = fopen(bullfile, "r")) isnt NULL)
  330.   {
  331.     while( fgets(tmp->scr, scrmax, port->fl) isnt NULL)
  332.     {
  333.        if (chkdis()) break;
  334.        prtx(tmp->scr);
  335.     }
  336.     fclose(port->fl);
  337.   }
  338.  
  339. /*
  340.  *  If not an expert user, give login message and
  341.  *  tell about unread messages.
  342.  */
  343.  
  344.   if (!(port->user->options & u_expert))
  345.     prtm(motd);
  346.     newmsg();
  347. }
  348.  
  349. /*
  350.  *  Execute a command to each port:
  351.  *  Connects ok, monitor on, etc.
  352.  */
  353.  
  354. allcmd(index)
  355. int index;
  356. {
  357.   register PORTS *p, *was;
  358.   byte ec;
  359.  
  360.   was = port;
  361.   for (p = porthd; p isnt NULL; p = p->next)
  362.   {
  363.     ioport(p);
  364.     if(p->dev is p_tnc)
  365.     {
  366.    p->flags clrbit p_give;
  367.    ec = p->ec;
  368.    p->ec = p->eccmds;
  369.    outstr(tcmds[index]);
  370.    waitcmd(0);
  371.    p->flags setbit p_give;
  372.    p->ec = ec;
  373.     }
  374.   }
  375.   ioport(was);
  376. }
  377.  
  378. alltnc(cp)
  379. char *cp;
  380. {
  381.   register PORTS *p, *was;
  382.   byte ec;
  383.  
  384.   was = port;
  385.   for (p = porthd; p isnt NULL; p = p->next) switch(p->dev)
  386.   {
  387.     case p_tnc:
  388.       ioport(p);
  389.       ec = p->ec;
  390.       p->ec = p->eccmds;
  391.       p->flags clrbit p_give;
  392.       outstr(cp);
  393.       waitcmd(0);
  394.       p->flags setbit p_give;
  395.       p->ec = ec;
  396.       break;
  397.  
  398.     default: ;
  399.   }
  400.   ioport(was);
  401. }
  402.  
  403. /*
  404.  *  Execute a command to the current port:
  405.  *  Connects ok, monitor on, etc.
  406.  */
  407.  
  408. onecmd(index)
  409. int index;
  410. {
  411.   register byte ec;
  412.  
  413.   if(port->dev is p_tnc)
  414.   {
  415.       ec = port->ec;
  416.       port->ec = port->eccmds;
  417.       port->flags clrbit p_give;
  418.       outstr(tcmds[index]);
  419.       waitcmd(0);
  420.       port->ec = ec;
  421.       port->flags setbit p_give;
  422.   }
  423. }
  424.  
  425. onetnc(cp)
  426. char *cp;
  427. {
  428.   register byte ec;
  429.  
  430.   if (port->dev is p_tnc)
  431.   {
  432.     ec = port->ec;
  433.     port->ec = port->eccmds;
  434.     port->flags clrbit p_give;
  435.     outstr(cp);
  436.     waitcmd(0);
  437.     port->ec = ec;
  438.     port->flags setbit p_give;
  439.   }
  440. }
  441.  
  442. /*
  443.  *  Need to distinguish between "disconect in progress", "disconnected",
  444.  *  "connected", "connect in progress".
  445.  */
  446.  
  447. issta(cp)
  448. char *cp;
  449. {
  450.   register char *p;
  451.  
  452.   p = cp;
  453.  
  454. #ifndef MCH_AMIGA
  455.   if (matchn(cp, "cmd:", 4)) p += 4;
  456. #else
  457. /* There could be more than one cmd: lurking on the line */
  458.    while (matchn(cp, "cmd:", 4)) strcpy(p,p+4);
  459.    /*PH Check for beginning of line from a KAM
  460.      of the form 'A/V' or 'A/H' */
  461.    if(p[1] == '/') {
  462.       strcpy(p,p+4);
  463.    }
  464. #endif
  465.  
  466.   if (!matchn(p, "Link sta", 8)) return false;
  467.  
  468.   if (matchn(p + 15, "DISC", 4) and (strlen(p) < 30)) port->mode = discon;
  469.   return true;
  470. }
  471.  
  472. /*
  473.  *  Put tnc in converse mode.
  474.  */
  475.  
  476. convtnc()
  477. {
  478.   register byte ec;
  479.  
  480.   if(port->dev is p_tnc)
  481.   {
  482.       ec = port->ec;
  483.       port->ec = port->eccmds;
  484.       outstr("conv\n");
  485.       port->ec = ec;
  486.       wait(2);
  487.   }
  488. }
  489.  
  490.  
  491. trantnc()
  492. {
  493.   register byte ec;
  494.  
  495.   if(port->dev is p_tnc)
  496.   {
  497.       ec = port->ec;
  498.       port->ec = port->eccmds;
  499.       outstr("trans\n");
  500.       port->flags setbit p_trans;
  501.       port->ec = ec;
  502.       wait(1);
  503.   }
  504. }
  505.  
  506. /*
  507.  *  Put tnc in command mode.
  508.  */
  509.  
  510. cmdtnc()
  511. {
  512.   register byte ec;
  513.  
  514.   if(port->dev is p_tnc)
  515.   {
  516.       ec = port->ec;
  517.       port->ec = port->eccmds;
  518.       port->flags clrbit p_give;
  519.       if (port->flags & p_trans) breakport(); else outchar(ctl_c);
  520.       waitcmd(1);
  521.       port->ec = ec;
  522.       port->flags setbit p_give;
  523.       port->flags clrbit p_trans;
  524.   }
  525. }
  526.  
  527. /*
  528.  *  Discover the state of the device on the current port.
  529.  */
  530.  
  531. tncstate()
  532. {
  533.    register byte ec;
  534.  
  535.    if(port->mode & idle) return;
  536.  
  537.    if(port->dev is p_tnc) {
  538.       ec = port->ec;
  539.       port->ec = port->eccmds;
  540.       cmdtnc();
  541.       port->flags clrbit p_give;
  542. #ifdef MCH_AMIGA
  543.       /* If this is the amiga version but it doesn't look like a
  544.          KAM then just use the usual code
  545.       */
  546.       if(!hfstream) {
  547. #endif
  548.          outstr("C\n");
  549.          while(true) {
  550.             getdat();
  551.             if(issta(port->line)) {
  552.                waitcmd(1);
  553.                port->ec = ec;
  554.                port->flags setbit p_give;
  555.                return;
  556.             }
  557.             else {
  558.                cmdtnc();
  559.                port->flags clrbit p_give;
  560.                outstr("C\n");
  561.             }
  562.          }
  563. #ifdef MCH_AMIGA
  564.       }
  565.       while(true) {
  566.          /* Try to get an HF status report. */
  567.          /* Ask for HF status first. The reason is that if both streams
  568.             are disconnected, then this procedure will leave the TNC on
  569.             the VHF stream during idle periods. So if you use the TAlk
  570.             command to talk to the TNC and just give it a Connect command
  571.             it will by default send it out the VHF port.
  572.          */
  573. Delay(10L);
  574.          outchar(hfstream);
  575.          outstr("AC\n");
  576.          getdat();
  577.          /* save the port mode before calling issta. If the HF port is
  578.             DISConnected it will force the mode to discon. This must be
  579.             restored to its original value as it was after the getdat
  580.             when the VHF port is tried because otherwise distnc() and
  581.             other routines will think the VHF side is disconnected even
  582.             if it is not, and they will not force a disconnect when one
  583.             is needed.
  584.             Also, saving the mode here immediately AFTER the first getdat
  585.             will preserve the 'forced' state if the SYSOP had used the
  586.             ^F to force the port to disconnect because we call getdat
  587.             again and the second call won't know the ^F has happened.
  588.          */
  589.          save_mode = port->mode;
  590.          if(issta(port->line)) {
  591.             /* It's a valid status line */
  592.             waitcmd(1);
  593.             /* If it returns not disconnected then it's the HF channel */
  594.             if(port->mode != discon) {
  595.                port->ec = ec;
  596.                port->flags setbit p_give;
  597.                return;
  598.             }
  599.             /* The HF channel is not connected so either the VHF port
  600.                is disconnected, in which case return OR it is connected
  601.                or connecting in which case we still return but force the
  602.                TNC onto the VHF channel
  603.             */
  604.             outchar(vhfstream);
  605.             outstr("AC\n");
  606.             /* now restore the port mode again - getdat will only override
  607.                the existing mode if something goes wrong so if the last
  608.                mode was forced, it will remain forced unless, for example,
  609.                it now sees a *** DISC.
  610.             */
  611.             port->mode = save_mode;
  612.             getdat();
  613.             if(issta(port->line)) {
  614.                waitcmd(1);
  615.                port->ec = ec;
  616.                port->flags setbit p_give;
  617.                return;
  618.             }
  619.          }
  620.          /* If can't get a valid status line from either then fire another
  621.             control C at the port and try again
  622.          */
  623.          cmdtnc();
  624.          port->flags clrbit p_give;
  625.       }
  626. #endif
  627.    }
  628. }
  629.  
  630. /*
  631.  *  Disconnect tnc.
  632.  */
  633. #ifdef MCH_AMIGA
  634. /* This is the last remaining busy-wait routine in cbbs. If it can be
  635.    removed then the settmr and chktmr routines can also be removed from
  636.    funcs.c
  637. */
  638. #endif
  639.  
  640. distnc()
  641. {
  642.    register int tsave;
  643.    register short done;
  644.    byte ec;
  645.  
  646.    tncstate();
  647.   
  648.    if(port->mode & idle) return;
  649.  
  650.    ec = port->ec;
  651.    port->ec = port->eccmds;
  652.    switch(port->dev) {
  653. #ifdef MCH_AMIGA
  654.    case p_nulmdm:
  655. #endif
  656.    case p_serial:
  657.       if(!(port->mode & discon)) outstr("*** DISCONNECTED\n");
  658.       break;
  659.    case p_tnc:
  660.       if (port->mode & discon) break;
  661.       port->flags clrbit p_give;
  662.       outstr("D\n");  /* This does not eat cmd:, thus dtime not used */
  663.       settmr(&port->expire, port->dtime);
  664.       while(true) {
  665.          if(instat()) {
  666.             tsave = port->ctime;
  667.             port->ctime = port->dtime;
  668.             getdat();
  669.             port->ctime = tsave;
  670. #ifndef MCH_AMIGA
  671.             if(isdis(port->line))
  672. #else
  673. /* FIX 12 */
  674.             if(isdis(port->line) || isother(port->line))
  675. #endif
  676.             {
  677.                waitcmd(1);
  678.                port->ec = ec;
  679.                port->flags setbit p_give;
  680.                return;
  681.             }
  682.          }
  683.  
  684.          if(!chktmr(port->expire)) {
  685.             outstr("D\n");
  686. #ifndef MCH_AMIGA
  687.             while(!isdis(port->line)) getdat();
  688. #else
  689. /* FIX 12 */
  690.             while(!isdis(port->line) && !isother(port->line)) getdat();
  691. #endif
  692.             waitcmd(1);
  693.             port->ec = ec;
  694.             port->flags setbit p_give;
  695.             return;
  696.          }
  697.       }
  698.       break;
  699.    }
  700.    port->ec = ec;
  701.    port->mode = discon;
  702. }
  703.  
  704. /*
  705.  *  Send connect string to tnc.
  706.  */
  707.  
  708. contnc(p)
  709. char *p;
  710. {
  711.   register byte ec;
  712. #ifdef MCH_AMIGA
  713.    register char *q;
  714. #endif
  715.  
  716.   ec = port->ec;
  717.   port->ec = true;
  718.   switch (port->dev)
  719.   {
  720.     case p_tnc:
  721.       outstr(p);
  722.       port->ec = port->eccmds;
  723. #ifndef MCH_AMIGA
  724. /*
  725.    DON'T DO THIS. MFJ (and some other TNCs) which, for proper BBS operation,
  726.    should have BBSMSGS ON and NEWMODE ON, does NOT send a cmd: prompt after
  727.    a Connect command. With any other combination of BBSMSGS and NEWMODE, the
  728.    stupid thing sends cmd: but the one combination that we need to work,
  729.    doesn't!
  730.    So the waitcmd(0) here will not see a cmd: prompt but it will see, AND
  731.    THROW AWAY, the *** CONNECTED message. This means that the loop which
  732.    will try ot find the CONNECTED message will fail.
  733. */
  734.       waitcmd(0);
  735. #endif
  736.       break;
  737.  
  738.     case p_serial:
  739. #ifdef MCH_AMIGA
  740.       outstr(p);
  741.       while(1) {
  742.          getdat();
  743.          q = port->line;
  744.          /* Ignore the error returns from getdat on a serial line. It looks
  745.             for carrier and dies if it isn't there. But we know it can't be
  746.             there yet.
  747.          */
  748.          if(*q == 0)continue;
  749.          if((*q == '\n') || (*q == '\r'))continue;
  750.          if((*q == 'A') && (*(q+1) == 'T'))continue;
  751.          if(matchn(q,"RING",4))continue;
  752.          if(matchn(q,"CONNECT",7))break;
  753.          port->mode = idle;
  754. printf("PORT IDLE\n");
  755.          return;
  756.       }
  757.       /* The other end, notably the ZyXEL, may not have seen its CONNECT
  758.          message yet ... so we must Delay here before sending the connect
  759.       */
  760.       Delay(250L);
  761.       port->mode = remote;
  762. #endif
  763. #ifdef MCH_AMIGA
  764.     case p_nulmdm:
  765. /* The initial \n will flush any garbage generated in the modem during
  766.    the connect procedure.
  767. */
  768.       prtx("\n*** CONNECTED to $O\n");
  769. #else
  770.       prtx("*** CONNECTED to $O\n");
  771. #endif
  772.   }
  773.   port->ec = ec;
  774. }
  775.  
  776. /*
  777.  *  Wait for "cmd:" prompt.
  778.  */
  779.  
  780. #ifndef MCH_AMIGA
  781. waitcmd(x)
  782. int x;
  783. {
  784.   static char *wanted = "cmd:";
  785.   register short i;
  786.   long l;
  787.   int t;
  788.   if (s_flag & s_dv) t = 5; else t = 2;
  789.   if (x) t = x;
  790.   if(port->dev is p_tnc)
  791.   {
  792.       settmr(&l, t);
  793.       for (i = 0; i < 4;)
  794.       {
  795.    if (instat()) if (inchar() is *(wanted + i)) i++; else i = 0;
  796.    if (!chktmr(l))
  797.    {
  798.        if (!(port->eccmds))
  799.        bdos(2,tolower(port->id),0); return;
  800.    }
  801.       }
  802.       if (!(port->eccmds)) bdos(2,port->id,0);
  803.   }
  804. }
  805. #endif
  806.